package com.example.asapp.demo.code;

import com.example.asapp.demo.code.vo.ColumnVO;
import com.example.asapp.demo.code.vo.EntityVO;
import com.example.asapp.demo.code.vo.ForeignKeyVO;
import com.github.mustachejava.DefaultMustacheFactory;
import com.github.mustachejava.Mustache;
import com.github.mustachejava.MustacheFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
@Slf4j
public class CodeService {

    @Autowired
    CodeMapper codeMapper;

    public EntityVO getEntity(EntityVO entityVO){
        List<ColumnVO> columnVOS=  codeMapper.getEntity(entityVO);
        entityVO.setTableComment(codeMapper.getComment(entityVO));
        columnVOS.forEach(e->{
            e.setName(lineToHump(e.getName()));
            e.setCname(getUpper(e.getName()));
            e.setJavaType(getJavaType(e.getDbType()));
            e.setJdbcType(getJdbcType(e.getDbType()));
            e.setDbType(e.getDbType().toUpperCase());
        });
        List<ForeignKeyVO> foreignKeyVOS=codeMapper.getForeign(entityVO);
        setVoName(foreignKeyVOS);
        entityVO.setForeignKeys(foreignKeyVOS);
        entityVO.setColumns(columnVOS);
        String tableName=entityVO.getTableName();
        String className=tableName.substring(tableName.lastIndexOf("_")+1);
        String packageName=tableName.substring(tableName.indexOf("_")+1,tableName.indexOf("_",2));
        entityVO.setPackageName(packageName);
        entityVO.setName(className);
        entityVO.setCname(getUpper(className));

        entityVO.setKeys(entityVO.getColumns().stream().filter(e-> e.isPrimaryKey()).collect(Collectors.toList()));
        entityVO.setNoKeys(entityVO.getColumns().stream().filter(e-> !e.isPrimaryKey()).collect(Collectors.toList()));


        return entityVO;
    }


    private String lineToHump(String str) {
        Pattern linePattern = Pattern.compile("_(\\w)");
        str = str.toLowerCase();
        Matcher matcher = linePattern.matcher(str);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

    private void setVoName(List<ForeignKeyVO> foreignKeyVOS) {
        foreignKeyVOS.forEach(e->{
            e.setReferenceVoName(tableToVoName(e.getReferencedTableName()));
            e.setVoName(tableToVoName(e.getTableName()));
        });
    }
    private String tableToVoName(String referenceTableName){
        String className=referenceTableName
                .substring(referenceTableName.lastIndexOf("_")+1);
        return className;

    }
    private String getJdbcType(String dbType) {
        System.out.println(dbType);
        String r="";
        switch (dbType){
            case "varchar":r="VARCHAR";break;
            case "int":r="INTEGER";break;
            default:break;
        }
        return  r;
    }

    private String getJavaType(String dbType) {
        String r="none";
        switch (dbType){
            case "int":r= "Integer";break;
            case "varchar":r= "String";break;
            default:
                r= "none";
                break;
        }
        return r;
    }

    public void setCode(EntityVO entityVO) throws IOException {
        // 预处理entityVO
        List<CodeFile> codeFiles=getCodePaths();
        for (ColumnVO column : entityVO.getColumns()) {
           log.info("cname is:{},name is :{}",
                   column.getCname(),column.getName());
        }
        for(CodeFile e :codeFiles){
            MustacheFactory mf = new DefaultMustacheFactory();
            Mustache mustache = mf.compile(e.getMustachePath());
            Map<String, Object> content = new HashMap<>();
            content.put("entity", entityVO);
            StringWriter writer = new StringWriter();
            mustache.execute(writer, content);
            catInto(writer.toString(),
                    getPath(entityVO,e.getNewPath(),e.getType()));
        };
    }

    private String getPath(EntityVO entityVO, String path, String type) {
        String pre=getPre(type);
        return pre+path.replace("{{cname}}",entityVO.getCname())
                .replace("{{name}}",entityVO.getName())
                .replace("{{packageName}}",entityVO.getPackageName());
    }

    private String getPre(String type) {
        String re="";
        switch (type){
            case "app":
                re=CodePath.appPath;
                break;
            case "web":
                re=CodePath.webPath;
                break;
            default:break;
        }
        return re;
    }


    String getUpper(String name){
        char[] chars=name.toCharArray();
        if(chars[0]>='a' && chars[0]<='z'){
            chars[0] = (char) (chars[0]-32);
        }
        String cname= new String(chars);
        return cname;
    }

    private void setCname(List<ColumnVO> columnVOS) {
        columnVOS.forEach(e->{
            e.setCname(getUpper(e.getName()));
        });
    }

    private List<CodeFile> getCodePaths() {

        List<CodeFile> codeFiles=new ArrayList<>();
        codeFiles.add(new CodeFile("mustache/java/Dao","java//com//example//asapp//{{packageName}}//{{name}}//{{cname}}Dao.java", "app"));
        codeFiles.add(new CodeFile("mustache/java/Api","java//com//example//asapp//{{packageName}}//{{name}}//{{cname}}Api.java", "app"));
        codeFiles.add(new CodeFile("mustache/java/Service","java//com//example//asapp//{{packageName}}//{{name}}//{{cname}}Service.java", "app"));
        codeFiles.add(new CodeFile("mustache/web/api","views//{{packageName}}//{{name}}//api.js", "web"));
        codeFiles.add(new CodeFile("mustache/web/list","views//{{packageName}}//{{name}}//list.vue", "web"));
        codeFiles.add(new CodeFile("mustache/web/form","views//{{packageName}}//{{name}}//form.vue", "web"));
        return codeFiles;
    }

    public static void catInto(String newContent, String newFilePath) throws IOException {
        File file = new File(newFilePath);
        System.out.println(newFilePath);
        File testPath = new File(file.getParent());
        testPath.delete();
        testPath.mkdirs();
        file.createNewFile();

        FileWriter fileWriter = new FileWriter(file.getAbsoluteFile());
        BufferedWriter bw = new BufferedWriter(fileWriter);
        bw.write(newContent);
        bw.close();
    }

//    public static void main(String[] args) {
//        System.out.println(lineToHump("other_info_r"));
//    }
}
